/***************************************************************************************

***************************************************************************************/

/*
*************************************************************************************
* File name: macroblock.c
* Function: Decode a Macroblock
*
*************************************************************************************
*/


#include "contributors.h"

#include <math.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>

#include "global.h"
#include "elements.h"
#include "macroblock.h"
#include "vlc.h"

#include "defines.h"
#include "block.h"
#include "transform.h"
#include "checksyntax.h"
//!EDIT START <added by  AEC
#include "AEC.h"
#include "pixel.h"
#include "intra-prediction.h"
#include "inter-prediction.h"

extern  short IQ_SHIFT[64];
extern  unsigned  short IQ_TAB[64];

void readMotionVector(img_params *img);
extern void tracebits3(const char *trace_str,  int len,  int info,int value1);  //ITM

#define MODE_IS_P8x8  (mbmode==11)
#define I16OFFSET     (mbmode-7)
#define fwd_ref_idx_to_refframe(idx) ((idx)+fwd_refframe_offset)
#define bwd_ref_idx_to_refframe(idx) ((idx)+bwd_refframe_offset)

extern void arideco_start_decoding(DecodingEnvironmentPtr dep, unsigned char *cpixcode,
	int firstbyte, int *cpixcode_len ); 
extern void init_contexts (img_params* img);
extern void arideco_done_decoding(DecodingEnvironmentPtr dep);
extern int DCT_Pairs;


/*
******************************************************************************
*  Function: calculated  frame distance between current frame
*            and the reference(frame).
*     Input: blkref 
fw_bw  
*    Output: distance for motion vector scale
*    Return: 
* Attention:
*    Author: 
******************************************************************************
*/
int calculate_distance(int blkref, int fw_bw )  //fw_bw>=0: forward ; fw_bw<0: backward
{
	int distance = 0;
	if ( img->type==P_IMG ) // P img
	{
		if(blkref==0)
			distance = picture_distance*2 - img->imgtr_last_P*2;
		else if((blkref >=1 && blkref <= img->max_ref_num && img->type == P_IMG) ||(img->type == B_IMG && blkref == 1))
			distance = picture_distance*2 - img->imgtr_last_prev_P*2;
		else
		{
			assert(0); //only two reference pictures for P frame
		}
	}
	else //B_IMG
	{
		if (fw_bw >=0 ) //forward
			distance = picture_distance*2 - img->imgtr_last_P*2;
		else
			distance = img->imgtr_next_P*2  - picture_distance*2;
	}

	distance = (distance+512)%512;	
	return distance;
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/
int scale_motion_vector(int motion_vector, int currblkref, int neighbourblkref, int ref)
{
	int sign = (motion_vector>0?1:-1);
	int mult_distance;
	int devide_distance;

	motion_vector = abs(motion_vector);

	if(motion_vector == 0)
		return 0;


	mult_distance = calculate_distance( currblkref, ref );
	devide_distance = calculate_distance(neighbourblkref, ref);

	motion_vector = sign*((motion_vector*mult_distance*(512/devide_distance)+256)>>9);

	return motion_vector;
}

/*
*************************************************************************
* Function:Checks the availability of neighboring macroblocks of
the current macroblock for prediction and context determination;
marks the unavailable MBs for intra prediction in the
past of the current MB are checked.
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/

void CheckAvailabilityOfNeighbors(img_params *img)
{
	int i,j;
	const int mb_width = img->width/MB_SIZE;
	const int mb_nr = img->current_mb_nr;
	Macroblock *currMB = &mb_data[mb_nr];
	int check_value;
	int remove_prediction;
	currMB->mb_available_up   = NULL; 
	currMB->mb_available_left = NULL;

	// mark all neighbors as unavailable
	for (i=0; i<3; i++)
		for (j=0; j<3; j++)
			mb_data[mb_nr].mb_available[i][j]=NULL;

	mb_data[mb_nr].mb_available[1][1]=currMB; // current MB

	// Check MB to the left
	if(img->pix_x >= MB_SIZE)
	{

		remove_prediction = currMB->slice_nr != mb_data[mb_nr-1].slice_nr;

		if (!remove_prediction)
		{
			currMB->mb_available[1][0]=&(mb_data[mb_nr-1]);
		}
	}

	// Check MB above
	check_value =  (img->pix_y >= MB_SIZE);
	if(check_value) 
	{

		remove_prediction = currMB->slice_nr != mb_data[mb_nr-mb_width].slice_nr;

		if (!remove_prediction)
		{
			currMB->mb_available[0][1]=&(mb_data[mb_nr-mb_width]);
		}
	}

	// Check MB left above
	if(img->pix_y >= MB_SIZE && img->pix_x >= MB_SIZE)
	{
		remove_prediction = currMB->slice_nr != mb_data[mb_nr-mb_width-1].slice_nr;

		if (!remove_prediction)
		{
			currMB->mb_available[0][0]=&(mb_data[mb_nr-mb_width-1]);
		}
	}

	// Check MB right above
	if(img->pix_y >= MB_SIZE && img->pix_x < (img->width-MB_SIZE ))
	{

		if(currMB->slice_nr == mb_data[mb_nr-mb_width+1].slice_nr)
			currMB->mb_available[0][2]=&(mb_data[mb_nr-mb_width+1]);

	}

	currMB->mbAddrA = mb_nr - 1;
	currMB->mbAddrB = mb_nr - img->PicWidthInMbs;
	currMB->mbAddrC = mb_nr - img->PicWidthInMbs + 1;
	currMB->mbAddrD = mb_nr - img->PicWidthInMbs - 1;

	currMB->mbAvailA = (currMB->mb_available[1][0]!=NULL)?1:0;
	currMB->mbAvailB = (currMB->mb_available[0][1]!=NULL)?1:0;
	currMB->mbAvailC = (currMB->mb_available[0][2]!=NULL)?1:0;
	currMB->mbAvailD = (currMB->mb_available[0][0]!=NULL)?1:0;
}

void set_MB_parameters (img_params *img, int mb)
{
	const int number_mb_per_row = img->width / MB_SIZE ;

	img->mb_x = mb % number_mb_per_row;
	img->mb_y = mb / number_mb_per_row;

	// Define vertical positions
	img->block_y = img->mb_y * 2;   // 8x8 block  // vertical luma block position
	img->pix_y   = img->mb_y * MB_SIZE;   // vertical luma macroblock position
	img->pix_c_y = img->mb_y * MB_SIZE/2; // vertical chroma macroblock position

	// Define horizontal positions
	img->block_x = img->mb_x * 2;    // 8x8 block    // luma block
	img->pix_x   = img->mb_x * MB_SIZE;     // luma pixel
	img->pix_c_x   = img->mb_x * MB_SIZE/2; // chroma pixel

}

/*
*************************************************************************
* Function:initializes the current macroblock
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/


void start_macroblock(img_params *img)
{
	int i,j,k,l;
	Macroblock *currMB;   // intialization code deleted, see below, StW

	assert (img->current_mb_nr >=0 && img->current_mb_nr < img->max_mb_nr);

	currMB = &mb_data[img->current_mb_nr];//GB

	/* Update coordinates of the current macroblock */
	img->mb_x = (img->current_mb_nr)%(img->width/MB_SIZE);
	img->mb_y = (img->current_mb_nr)/(img->width/MB_SIZE);

	/* Define vertical positions */
	img->block_y = img->mb_y * BLOCK_SIZE/2;      /* luma block position */
	img->pix_y   = img->mb_y * MB_SIZE;   /* luma macroblock position */
	img->pix_c_y = img->mb_y * MB_SIZE/2; /* chroma macroblock position */

	/* Define horizontal positions */
	img->block_x = img->mb_x * BLOCK_SIZE/2;      /* luma block position */ 
	img->pix_x   = img->mb_x * MB_SIZE;   /* luma pixel position */
	img->pix_c_x = img->mb_x * MB_SIZE/2; /* chroma pixel position */

	// If MB is next to a slice boundary, mark neighboring blocks unavailable for prediction
	CheckAvailabilityOfNeighbors(img);      // support only slice mode 0 in MBINTLC1 at this time
	CheckAvailabilityOfNeighborsAEC();

	// Reset syntax element entries in MB struct
	currMB->qp          = img->qp ;
	currMB->mb_type     = 0;
	currMB->delta_quant = 0;
	currMB->cbp         = 0;
	currMB->cbp_blk     = 0;
	currMB->c_ipred_mode= DC_PRED_8; 

	for (l=0; l < 2; l++)
		for (j=0; j < BLOCK_MULTIPLE; j++)
			for (i=0; i < BLOCK_MULTIPLE; i++)
				for (k=0; k < 2; k++)
					currMB->mvd[l][j][i][k] = 0;

	currMB->cbp_bits   = 0;

	for (j=0; j<MB_SIZE; j++)
		for (i=0; i<MB_SIZE; i++)
			img->m7[i][j] = 0;

	for (j=0; j<2*BLOCK_SIZE; j++)     
		for (i=0; i<2*BLOCK_SIZE; i++)   
		{
			img->m8[0][i][j] = 0;          
			img->m8[1][i][j] = 0;          
			img->m8[2][i][j] = 0;          
			img->m8[3][i][j] = 0;          
		}

		currMB->lf_disable = loop_filter_disable;
		for (i = 0; i < 4; i++) {
			currMB->splite_flag[i] = 0;
		}
}


/*
*************************************************************************
* Function:Interpret the mb mode for I-Frames
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/

void interpret_mb_mode_I(img_params *img)
{
	int i;
	Macroblock *currMB   = &mb_data[img->current_mb_nr];

	currMB->mb_type = I_MB;

	for (i=0;i<4;i++)
	{
		currMB->b8mode[i]=IBLOCK; 
		currMB->b8pdir[i]=-1; 
	}
}

/*
*************************************************************************
* Function:init macroblock I and P frames
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/

void init_macroblock(img_params *img)
{
	int i,j;
	Macroblock *currMB = &mb_data[img->current_mb_nr];//GB current_mb_nr];
	img->mv[img->block_x+4][img->block_y][2]=img->number;

	for (i=0;i<2;i++)
	{                           // reset vectors and pred. modes
		for(j=0;j<2;j++)
		{
			img->mv[img->block_x+i+4][img->block_y+j][0] = 0;
			img->mv[img->block_x+i+4][img->block_y+j][1] = 0;
			img->bimv[img->block_x+i+4][img->block_y+j][0] = 0;
			img->bimv[img->block_x+i+4][img->block_y+j][1] = 0;
		}
	}

	// Set the reference frame information for motion vector prediction
	if (IS_INTRA (currMB))
	{
		for (j=0; j<2; j++)
			for (i=0; i<2; i++)
			{
				refFrArr[img->block_y+j][img->block_x+i] = -1;
			}
	}
	else if (!IS_P8x8 (currMB))
	{
		for (j=0; j<2; j++)
			for (i=0; i<2; i++)
			{
				refFrArr[img->block_y+j][img->block_x+i] = 0;
			}
	}
	else
	{
		for (j=0; j<2; j++)
			for (i=0; i<2; i++)
			{
				refFrArr[img->block_y+j][img->block_x+i] = (currMB->b8mode[2*j+i]==IBLOCK ? -1 : 0);
			}
	}
	if(img->type == P_IMG)
	{  
		if(img->number >1 && img->type  == P_IMG && (currMB->mb_type == 1 || currMB->mb_type == 8
			|| currMB->mb_type == 2 || currMB->mb_type == 3 ))
		{
			for (j=0; j<2; j++)
				for (i=0; i<2; i++)
				{                
					refFrArr[img->block_y+j][img->block_x+i] = currMB->fw_ref[j*2 + i];
				} 
		}
	}
}

/*
*************************************************************************
* Function:Sets mode for 8x8 block
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/

void SetB8Mode (img_params* img, Macroblock* currMB, int value, int i)
{
	static const int p_v2b8 [ 5] = {4, 4, 6, 7, IBLOCK};
	static const int p_v2pd [ 5] = {0, 3, 0, 0, -1};
	static const int b_v2b8 [14] = {0, 4, 4, 4, 5, 6, 5, 6, 5, 6, 7, 7, 7, IBLOCK};
	static const int b_v2pd [14] = {2, 0, 1, 2, 0, 0, 1, 1, 2, 2, 0, 1, 2, -1};

	if (img->type==B_IMG)
	{
		currMB->b8mode[i]   = b_v2b8[value];
		currMB->b8pdir[i]   = b_v2pd[value];
	}
	else
	{
		currMB->b8mode[i]   = p_v2b8[value];
		currMB->b8pdir[i]   = p_v2pd[value];
	}

}

/*
*************************************************************************
* Function:Get the syntax elements from the NAL
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/

int read_one_macroblock(img_params *img)
{
	int i, j;

	SyntaxElement currSE;
	Macroblock *currMB = &mb_data[img->current_mb_nr];//GB current_mb_nr];
	int  img_block_y;
	int  tempcbp = 0;
	int fixqp;
	//!EDIT START <added by  AEC
	Slice *currSlice = img->currentSlice;
	DataPartition *dP;
	//!EDIT END <added by  AEC

	fixqp = (fixed_picture_qp || fixed_slice_qp);

	for (i = 0; i < 8; i++) {
		for (j = 0; j < 8; j++)
		{
			img->m8[0][i][j] = 0;
			img->m8[1][i][j] = 0;
			img->m8[2][i][j] = 0;
			img->m8[3][i][j] = 0;
		}
	}

	currMB->trans_type = TRANS_NxN;
	currMB->qp = img->qp;
	currSE.type = SE_MBTYPE;
	currSE.mapping = linfo_ue;
	currSE.value1 = 0;

	if (img->type != I_IMG)
	{
		CheckAvailabilityOfNeighborsAEC();

#if TRACE
		strncpy(currSE.tracestring, "MB Type", TRACESTRING_SIZE);
#endif
		dP = &(currSlice->partArr[0]);
		currSE.reading = readMBPartTypeInfo_AEC;
		dP->readSyntaxElement(&currSE, img, dP);

		currMB->mb_type = currSE.value1;
		img->cod_counter--;
		currSE.type    = SE_MBTYPE;    

		if (img->type == B_IMG)
		{
			// derive the mode of the macroblock
			if(currMB->mb_type == 0){
				for(i=0;i<4;i++) {
					currMB->b8mode[i]=0;         
					currMB->b8pdir[i]=2;
				}
				currMB->cbp = 0;
				return DECODE_MB;
			}
			else if(currMB->mb_type == 1){
				for(i=0;i<4;i++) 
				{
					currMB->b8mode[i] = 1;
				}
			}
			else if(currMB->mb_type == 2){
				currMB->mb_type = 3;
				for(i=0;i<4;i++)
				{
					currMB->b8mode[i]=3;
				}
			}else if(currMB->mb_type == 3){
				currMB->mb_type=2;
				for(i=0;i<4;i++)
				{
					currMB->b8mode[i]=2;
				}
			}else if (currMB->mb_type == 4) {		// B_Intra
				currMB->mb_type=I_MB;
				currMB->cbp=63;
				for(i=0;i<4;i++){
					currMB->b8mode[i]=IBLOCK;
					currMB->b8pdir[i]=-1;
				}
			}else if (currMB->mb_type == 5) {		// B_8x8
				currMB->mb_type=P8x8;
			}

			// derive the prediction direction of macroblock
			if(currMB->mb_type != 0 && currMB->mb_type != I_MB){
				const int maptab[] = {1, -1, 0, 2};
				if(currMB->mb_type == 1) {		// B_16x16
					currSE.mapping = linfo_ue;
	#if TRACE
					strncpy(currSE.tracestring, "16x16 mode", TRACESTRING_SIZE);
	#endif
					//mb_part_type is fix length coding(fix length equal 2)
					assert(currStream->streamBuffer != NULL);
					dP = &(currSlice->partArr[0]);
					currSE.reading = read_other_PredTypeInfo_AEC;
					dP->readSyntaxElement(&currSE, img, dP);

					for(i=0;i<4;i++) {
						currMB->b8pdir[i] = maptab[currSE.value1];
					}
				}
				else if (currMB->mb_type == 2 || currMB->mb_type == 3) {		// 1 : B_8x16,  2 : B_16x8
					int PredMode[2] = { -1, -1 };					
					for (i = 0; i < 2; i++)
					{
						currSE.mapping = linfo_ue;
	#if TRACE
						strncpy(currSE.tracestring, "8x16 mode or 16x8 mode", TRACESTRING_SIZE);
	#endif
						assert(currStream->streamBuffer != NULL);
						dP = &(currSlice->partArr[0]);
						currSE.reading = read_other_PredTypeInfo_AEC;
						dP->readSyntaxElement(&currSE, img, dP);
						PredMode[i] = currSE.value1;
					}

					if(currMB->mb_type == 3){
						currMB->b8pdir[0] = currMB->b8pdir[2] = maptab[PredMode[0]];
						currMB->b8pdir[1] = currMB->b8pdir[3] = maptab[PredMode[1]];
					}
					else{
						currMB->b8pdir[0] = currMB->b8pdir[1] = maptab[PredMode[0]];
						currMB->b8pdir[2] = currMB->b8pdir[3] = maptab[PredMode[1]];
					}
				}
				
				else if (currMB->mb_type == P8x8) {		// B_8x8
					for (i = 0; i < 4; i++) {
						currSE.mapping = linfo_ue;
	#if TRACE
						strncpy(currSE.tracestring, "8x8 mode", TRACESTRING_SIZE);
	#endif
						//mb_part_type is fix length coding(fix length equal 2)
						assert(currStream->streamBuffer != NULL);
						dP = &(currSlice->partArr[0]);
						currSE.reading = read_8x8_PredTypeInfo_AEC;
						dP->readSyntaxElement(&currSE, img, dP);
						SetB8Mode (img, currMB, currSE.value1, i);
					}
				}
				else {
					printf("Entropy Syntax Error! - read_one_macroblock(), B_Macroblock_Type : %d\n", currMB->mb_type);
					exit(0);
				}
			}
		}
		else if (img->type == P_IMG)
		{
			// derive the mode of the macroblock
			if (currMB->mb_type == 0) { // 2Nx2N or SKIP, which are distinguished by the prediction direction
				currMB->mb_type = 0;
				for(i=0;i<4;i++)
				{
					currMB->b8mode[i] = 0;
				}
			}else if (currMB->mb_type == 1){ // 1 : P_8x16
				currMB->mb_type=3;       
				for(i=0;i<4;i++)
				{
					currMB->b8mode[i]=3;
				}
			}else if (currMB->mb_type == 2){  // 2 : P_16x8
				currMB->mb_type=2;
				for(i=0;i<4;i++)
				{
					currMB->b8mode[i]=2;
				}
			}else if (currMB->mb_type == 3) {		// P_Intra
				currMB->mb_type = I_MB;
				for (i=0;i<4;i++){
					currMB->b8mode[i] = IBLOCK;
				}
			}else if (currMB->mb_type == 4) {		// P_8x8
				currMB->mb_type = P8x8;
			}

			// derive the prediction direction of macroblock
			if (currMB->mb_type == 0) {		// P_16x16
				currSE.mapping = linfo_ue;
#if TRACE
				strncpy(currSE.tracestring, "16x16 mode", TRACESTRING_SIZE);
#endif
				assert(currStream->streamBuffer != NULL);
				dP = &(currSlice->partArr[0]);
				currSE.reading = MHMC_read_16x16_PredTypeInfo_AEC;
				dP->readSyntaxElement(&currSE, img, dP);

				switch (currSE.value1) {
				case 0:
					for(i=0;i<4;i++)
					{
						currMB->b8pdir[i] = 0;
					}
					break;
				case 2:
					currMB->mb_type = 1;
					for (i=0;i<4;i++)
					{
						currMB->b8mode[i]   = 1;
						currMB->b8pdir[i]   = 0;
					}
					break;
				case 3:
					currMB->mb_type = 1;
					for (i=0;i<4;i++)
					{
						currMB->b8mode[i]   = 1;
						currMB->b8pdir[i]   = 3;
					}
					break;
				default:
					printf("Entropy Syntax Error! - read_one_macroblock(), P_16x16_Pred_Type : %d, %d\n", currSE.value1);
					exit(0);
				}
			}
			else if (currMB->mb_type == 2 || currMB->mb_type == 3) {
				int PredMode[2] = { -1, -1 };
				const int fwd = 0, mh = 1;
				const int maptab[] = {0, 3};
				for (i = 0; i < 2; i++) {
					currSE.mapping = linfo_ue;
#if TRACE
					strncpy(currSE.tracestring, "8x16 mode or 16x8 mode", TRACESTRING_SIZE);
#endif
					assert(currStream->streamBuffer != NULL);
					dP = &(currSlice->partArr[0]);
					currSE.reading = MHMC_read_other_PredTypeInfo_AEC;
					dP->readSyntaxElement(&currSE, img, dP);
					PredMode[i] = currSE.value1;
				}

				if(currMB->mb_type == 3){
					currMB->b8pdir[0] = currMB->b8pdir[2] = maptab[PredMode[0]];
					currMB->b8pdir[1] = currMB->b8pdir[3] = maptab[PredMode[1]];
				}
				else{
					currMB->b8pdir[0] = currMB->b8pdir[1] = maptab[PredMode[0]];
					currMB->b8pdir[2] = currMB->b8pdir[3] = maptab[PredMode[1]];
				}
			}
			else if (currMB->mb_type == I_MB) {
				currMB->cbp=63;
				for (i=0;i<4;i++)
				{
					currMB->b8pdir[i] = -1;
				}
			}
			else if (currMB->mb_type == P8x8) {
				for (i = 0; i < 4; i++) {
					currSE.mapping = linfo_ue;
#if TRACE
					strncpy(currSE.tracestring, "8x8 mode", TRACESTRING_SIZE);
#endif

					//mb_part_type is fix length coding(fix length equal 2)
					assert(currStream->streamBuffer != NULL);
					dP = &(currSlice->partArr[0]);
					currSE.reading = MHMC_read_other_PredTypeInfo_AEC;
					dP->readSyntaxElement(&currSE, img, dP);
					SetB8Mode (img, currMB, currSE.value1, i);
				}
			}
			else {
				printf("Entropy Syntax Error! - read_one_macroblock(), P_Macroblock_Type : %d\n", currMB->mb_type);
				exit(0);
			}
		}
	}else{
		interpret_mb_mode_I(img);
	}

	if (IS_INTRA(currMB) && abt_enable)
	{
		currSE.mapping = linfo_ue;
		assert(currStream->streamBuffer != NULL);
		dP = &(currSlice->partArr[0]);
		currSE.reading = readMBTransType_AEC;
		dP->readSyntaxElement(&currSE, img, dP);
		currMB->trans_type = currSE.value1;
	}

	if (abt_enable && currMB->mb_type == 1) {
		currMB->trans_type = TRANS_2Nx2N;
	}

	if (img->type == P_IMG && img->max_ref_num > 1 && img->number > 1)
	{
		int ref_num[10] = {0, 1, 3, 7, 11, 15, 19, 23, 27, 31};

		currSE.type = SE_MBTYPE;

		if (currMB->mb_type == P8x8)
			for (i = 0; i < 4; i++)
			{
				currSE.mapping = linfo_ue;
				assert(currStream->streamBuffer != NULL);
				dP = &(currSlice->partArr[0]);
				currSE.reading = read_Reffrm_AEC;
				dP->readSyntaxElement(&currSE, img, dP);
				if (currSE.value1 < 0 || currSE.value1 > 9) {
					printf("Reference Frame Index Error!\n");
					exit(0);
				}
				currSE.value1 = ref_num[currSE.value1];
				currMB->fw_ref[i] = currSE.value1;

			}
		else if (currMB->mb_type == 1)
		{
			currSE.mapping = linfo_ue;
			assert(currStream->streamBuffer != NULL);
			dP = &(currSlice->partArr[0]);
			currSE.reading = read_Reffrm_AEC;
			dP->readSyntaxElement(&currSE, img, dP);
			if (currSE.value1 < 0 || currSE.value1 > 9) {
				printf("Reference Frame Index Error!\n");
				exit(0);
			}
			currSE.value1 = ref_num[currSE.value1];

			currMB->fw_ref[0] = currMB->fw_ref[1] = currMB->fw_ref[2] = currMB->fw_ref[3] = currSE.value1;

		}

		else if (currMB->mb_type == 2 || currMB->mb_type == 3)
		{
			for (i = 0; i < 2; i++)
			{
				currSE.mapping = linfo_ue;
				assert(currStream->streamBuffer != NULL);
				dP = &(currSlice->partArr[0]);
				currSE.reading = read_Reffrm_AEC;
				dP->readSyntaxElement(&currSE, img, dP);

				if (currSE.value1 < 0 || currSE.value1 > 9) {
					printf("Reference Frame Index Error!\n");
					exit(0);
				}
				currSE.value1 = ref_num[currSE.value1];

				if (currMB->mb_type == 2)
				{
					if (i == 0)
						currMB->fw_ref[0] = currMB->fw_ref[1] = currSE.value1;
					else
						currMB->fw_ref[2] = currMB->fw_ref[3] = currSE.value1;
				}
				else
				{
					if (i == 0)
						currMB->fw_ref[0] = currMB->fw_ref[2] = currSE.value1;
					else
						currMB->fw_ref[1] = currMB->fw_ref[3] = currSE.value1;
				}
			}
		}
	}

	//--- init macroblock data ---
	if (img->type==B_IMG) 
		init_macroblock_Bframe(img);
	else
		init_macroblock       (img);

	if (IS_INTRA(currMB))
	{
		if (currMB->trans_type == TRANS_2Nx2N) {
			read_ipred_block_modes(img,0, 0);
			read_ipred_block_modes(img,4, 0);
		}
		else {
			int b8, b4;

			for (b8 = 0; b8 < 4; b8++) {
				dP = &(currSlice->partArr[0]);
				currSE.reading = readIntraSplite_AEC;
				dP->readSyntaxElement(&currSE, img, dP);
				currMB->splite_flag[b8] = currSE.value1;
			}

			for (b8 = 0; b8 < 4; b8++) {
				int cnt = currMB->splite_flag[b8] == 0 ? 1 : 4;
				for (b4 = 0; b4 < cnt; b4++) {
					read_ipred_block_modes(img, b8, b4);
				}
			}
			read_ipred_block_modes(img, 4, 0);
		}
	}

	if (IS_COPY(currMB)) //keep last macroblock
	{
		int i, j, pmv[2];
		int ***tmp_mv = img->mv;
		int mb_available_up   = (img->mb_y == 0)  ? 0 : (currMB->slice_nr == mb_data[img->current_mb_nr-img->PicWidthInMbs].slice_nr);
		int mb_available_left = (img->mb_x == 0)  ? 0 : (currMB->slice_nr == mb_data[img->current_mb_nr-1].slice_nr);
		int zeroMotionAbove = !mb_available_up ? 1 : refFrArr[img->block_y - 1][img->block_x] == 0 && tmp_mv[4 + img->block_x][img->block_y - 1][0] == 0 && tmp_mv[4 + img->block_x][img->block_y - 1][1] == 0 ? 1 : 0;
		int zeroMotionLeft = !mb_available_left ? 1 : refFrArr[img->block_y][img->block_x - 1] == 0 && tmp_mv[4 + img->block_x - 1][img->block_y][0] == 0 && tmp_mv[4 + img->block_x - 1][img->block_y][1] == 0 ? 1 : 0;

		currMB->cbp = 0;

		img_block_y = img->block_y;

		if (zeroMotionAbove || zeroMotionLeft) {
			for (i = 0; i < 2; i++) {
				for (j = 0; j < 2; j++) {
					img->mv[img->block_x + i + BLOCK_SIZE][img->block_y + j][0] = 0;
					img->mv[img->block_x + i + BLOCK_SIZE][img->block_y + j][1] = 0;
				}
			}
		} else {
			SetMotionVectorPredictor(img, pmv, pmv + 1, 0, refFrArr, img->mv, 0, 0, 16, 0);
			for (i = 0; i < 2; i++) {
				for (j = 0; j < 2; j++) {
					img->mv[img->block_x + i + BLOCK_SIZE][img_block_y + j][0] = pmv[0];
					img->mv[img->block_x + i + BLOCK_SIZE][img_block_y + j][1] = pmv[1];
				}
			}
		}

		for (j = 0; j < 2; j++) {
			for (i = 0; i < 2; i++) {
				refFrArr_frm[img->block_y + j][img->block_x + i] = 0;
			}
		}

		return DECODE_MB;
	}

	readMotionVector(img);

	// read CBP if not new intra mode
	if (!(IS_COPY(currMB) || (IS_DIRECT(currMB) && img->cod_counter >= 0)))
	{
		if (IS_INTRA(currMB))
			currSE.type = SE_CBP_INTRA;
		else
			currSE.type = SE_CBP_INTER;

		if (IS_INTRA(currMB))
			currSE.mapping = linfo_cbp_intra;
		else
			currSE.mapping = linfo_cbp_inter;

#if TRACE
		snprintf(currSE.tracestring, TRACESTRING_SIZE, "CBP");
#endif

		if (img->type == I_IMG || IS_INTER(currMB)) {
			currSE.golomb_maxlevels = 0;
		}

		dP = &(currSlice->partArr[0]);
		currSE.reading = readCBP_AEC;
		dP->readSyntaxElement(&currSE, img, dP);
		currMB->cbp = currSE.value1;

		if (chroma_format == 1)
		{
			if (currMB->cbp != 0)
				tempcbp = 1;
			else
				tempcbp = 0;
		}

		// Delta quant only if nonzero coeffs
		if (!fixqp && (tempcbp))
		{
			if (IS_INTER(currMB))
				currSE.type = SE_DELTA_QUANT_INTER;
			else
				currSE.type = SE_DELTA_QUANT_INTRA;

#if TRACE
			snprintf(currSE.tracestring, TRACESTRING_SIZE, "Delta quant ");
#endif
			dP = &(currSlice->partArr[0]);
			currSE.reading = readDquant_AEC;
			dP->readSyntaxElement(&currSE, img, dP);

			currMB->delta_quant = currSE.value1;
			//CHECKDELTAQP  //ITM
			img->qp = (img->qp - MIN_QP + currMB->delta_quant + (MAX_QP - MIN_QP + 1)) % (MAX_QP - MIN_QP + 1) + MIN_QP;
		}

		if (fixqp)
		{
			currMB->delta_quant = 0;
			img->qp = (img->qp - MIN_QP + currMB->delta_quant + (MAX_QP - MIN_QP + 1)) % (MAX_QP - MIN_QP + 1) + MIN_QP;

		}

	}
	// read CBP and Coeffs  ***************************************************************
	readCBPandCoeffsFromStream(img);

	return DECODE_MB;
}

void read_ipred_block_modes(img_params *img,int b8, int b4)
{
	int bi,bj,dec;
	int b4i, b4j;
	SyntaxElement currSE;
	Macroblock *currMB;
	int j2;
	int IntraChromaPredModeFlag;
	Slice *currSlice = img->currentSlice;
	DataPartition *dP;

	currSE.value1 = 0;
	currMB=mb_data+img->current_mb_nr;//current_mb_nr;
	IntraChromaPredModeFlag = IS_INTRA(currMB);

#if TRACE
	strncpy(currSE.tracestring, "Ipred Mode", TRACESTRING_SIZE);
#endif

	if (b8 < 4) {
		if (currMB->b8mode[b8] == IBLOCK) {
			IntraChromaPredModeFlag = 1;
			dP = &(currSlice->partArr[0]);
			currSE.reading = readIntraPredMode_AEC;
			dP->readSyntaxElement(&currSE, img, dP);

			//get from array and decode
			bi = img->block_x + (b8 & 1);
			bj = img->block_y + (b8 / 2);
			dec = currSE.value1;
			//set
			b4i = bi * 2 + (b4 & 1);
			b4j = bj * 2 + (b4 / 2);
			img->ipredmode[b4i + 1][b4j + 1] = dec;
			j2 = bj;
		}
	}

	if( b8==4&&currMB->b8mode[b8-3]==IBLOCK)
	{
		// 		currSE.type = SE_INTRAPREDMODE;
#if TRACE
		strncpy(currSE.tracestring, "Chroma intra pred mode", TRACESTRING_SIZE);
#endif
		dP = &(currSlice->partArr[0]);
		currSE.reading= readCIPredMode_AEC;
		dP->readSyntaxElement(&currSE,img,dP);

		currMB->c_ipred_mode = currSE.value1;

		if (currSE.value1 < DC_PRED_8 || currSE.value1 > PLANE_8)
		{
			printf("%d\n", img->current_mb_nr);
			error("illegal chroma intra pred mode!\n", 600);
		}
	}
}

/*
*************************************************************************
* Function:Set context for reference frames
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/

int BType2CtxRef (int btype)
{
	if (btype<4)
		return 0;
	else
		return 1;
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/
void readMotionVector(img_params *img)
{
	int i,j,k,l,m,n;
	int step_h,step_v;
	int curr_mvd;
	Macroblock *currMB  = &mb_data[img->current_mb_nr];
	SyntaxElement currSE;
	int bframe          = (img->type==B_IMG);
	int partmode        = (IS_P8x8(currMB)?4:currMB->mb_type);
	int step_h0         = BLOCK_STEP [partmode][0];
	int step_v0         = BLOCK_STEP [partmode][1];
	Slice *currSlice    = img->currentSlice;
	DataPartition *dP;

	int mv_mode, i0, j0, refframe;
	int pmv[2];
	int j4, i4, ii,jj;
	int vec;

	int iTRb,iTRp,iTRd;
	int frame_no_next_P, frame_no_B, delta_P, delta_P_scale; 
	int ref;
	int img_block_y;
	int use_scaled_mv;
	int fw_refframe,current_tr;

	int	scale_refframe,iTRp1;

	currSE.value1 = 0;
	if (bframe && IS_P8x8 (currMB))
	{
		for (i=0;i<4;i++)
		{
			if (currMB->b8mode[i] == 0)
			{
				for(j=i/2;j<i/2+1;j++)
				{
					for(k=(i%2);k<(i%2)+1;k++)
					{
						//sw
						img->fw_refFrArr[img->block_y + j][img->block_x + k] = 0;
						img->bw_refFrArr[img->block_y + j][img->block_x + k] = 0; 
					}
				}
			}
		}
	} 


	//=====  READ FORWARD MOTION VECTORS =====
	currSE.type = SE_MVD;

	currSE.mapping = linfo_se;

	for (j0=0; j0<2; )
	{
		if(currMB->mb_type!=I_MB)
		{				
			step_h0         = (BLOCK_STEP[(currMB->mb_type==P8x8)? 4 : currMB->mb_type][0]);
			step_v0         = (BLOCK_STEP[(currMB->mb_type==P8x8)? 4 : currMB->mb_type][1]);
		}

		if((currMB->mb_type==I_MB&&j0==0)) 
		{ j0 += 1; continue;}

		for (i0=0; i0<2; )
		{
			k=2*j0+i0;
			if ((currMB->b8pdir[k]==0 || currMB->b8pdir[k]==2 || currMB->b8pdir[k]==3) && (currMB->b8mode[k] !=0))
			{
				mv_mode  = currMB->b8mode[k];
				step_h   = BLOCK_STEP [mv_mode][0];
				step_v   = BLOCK_STEP [mv_mode][1];

				if (!bframe)  refframe = refFrArr        [img->block_y+j0][img->block_x+i0];
				else                                     refframe = img->fw_refFrArr[img->block_y+j0][img->block_x+i0];


				for (j=j0; j<j0+step_v0; j+=step_v)
					for (i=i0; i<i0+step_h0; i+=step_h)
					{
						j4 = img->block_y+j;
						i4 = img->block_x+i;

						// first make mv-prediction
						if (!bframe)  
							SetMotionVectorPredictor (img, pmv, pmv+1, refframe, refFrArr,         img->mv,    i, j, 8*step_h, 0);
						else               
							SetMotionVectorPredictor (img, pmv, pmv+1, refframe, img->fw_refFrArr, img->fw_mv, i, j, 8*step_h, 0);


						for (n=0; n < 2; n++) 
						{
#if TRACE
							snprintf(currSE.tracestring, TRACESTRING_SIZE, "FMVD (pred %d)",pmv[n]);
#endif
							img->subblock_x = i; // position used for context determination
							img->subblock_y = j; // position used for context determination
							currSE.value2 = (!bframe ? n : 2*n); // identifies the component; only used for context determination

							img->subblock_x = i; // position used for context determination
							img->subblock_y = j; // position used for context determination
							dP = &(currSlice->partArr[0]);
							currSE.reading = readMVD_AEC;
							currSE.value2 = (n<<1)+0; // identifies the component; only used for context determination
							dP->readSyntaxElement(&currSE,img,dP);
	
							curr_mvd = currSE.value1; 
							//CHECKMVDRANGE        // mv range, ITM

							vec=curr_mvd+pmv[n];           /* find motion vector */

							// need B support
							if (!bframe)
							{
								for(ii=0;ii<step_h;ii++)
									for(jj=0;jj<step_v;jj++)
										img->mv[i4+ii+BLOCK_SIZE][j4+jj][n]=vec;
								for(ii=0;ii<step_h;ii++)
									for(jj=0;jj<step_v;jj++)
										img->bimv[i4+ii+BLOCK_SIZE][j4+jj][n]=pmv[n];
							}
							else      // B frame
							{        
								for(ii=0;ii<step_h;ii++)
									for(jj=0;jj<step_v;jj++)
										img->fw_mv[i4+ii+BLOCK_SIZE][j4+jj][n]=vec;
							}

							/* store (oversampled) mvd */
							for (l=0; l < step_v; l++) 
								for (m=0; m < step_h; m++)  
									currMB->mvd[0][j+l][i+m][n] =  curr_mvd;
						}
					}
			}
			else if (currMB->b8mode[k=2*j0+i0]==0)      
			{// direct mode         
				for (j=j0; j<j0+step_v0; j++)
					for (i=i0; i<i0+step_h0; i++)
					{   

						ref= refFrArr[img->block_y+j][img->block_x+i];
						img_block_y = (img->current_mb_nr%2) ? (img->block_y-4)/2:img->block_y/2;

						if(ref == -1)
						{
							img->fw_refFrArr[img->block_y+j][img->block_x+i]=0; 
							img->bw_refFrArr[img->block_y+j][img->block_x+i]=0; 
							j4 = img->block_y+j;
							i4 = img->block_x+i;  

							for (ii=0; ii < 2; ii++) 
							{
								img->fw_mv[i4+BLOCK_SIZE][j4][ii]=0;
								img->bw_mv[i4+BLOCK_SIZE][j4][ii]=0;
							}

							SetMotionVectorPredictor(img,&(img->fw_mv[i4+BLOCK_SIZE][j4][0]),
								&(img->fw_mv[i4+BLOCK_SIZE][j4][1]),0,img->fw_refFrArr, 
								img->fw_mv,0,0,16, 0);
							SetMotionVectorPredictor(img,&(img->bw_mv[i4+BLOCK_SIZE][j4][0]),
								&(img->bw_mv[i4+BLOCK_SIZE][j4][1]),0,img->bw_refFrArr, 
								img->bw_mv,0,0,16, -1);					
						}
						else
						{
							frame_no_next_P =2*img->imgtr_next_P;
							frame_no_B = 2*img->pic_distance; 

							delta_P = 2* (img->imgtr_next_P - img->imgtr_last_P);
							delta_P = (delta_P + 512)%512;         
							delta_P_scale = 2*(img->imgtr_next_P - img->imgtr_last_prev_P);		
							delta_P_scale = (delta_P_scale + 512)%512;						
							scale_refframe = 0;

							iTRp  = ref==0 ? delta_P : delta_P_scale;				
							iTRp1 = scale_refframe==0 ? delta_P : delta_P_scale;	

							iTRd = frame_no_next_P - frame_no_B;
							iTRb = iTRp1 - iTRd;

							iTRp  = (iTRp  + 512)%512;
							iTRp1 = (iTRp1 + 512)%512;
							iTRd  = (iTRd  + 512)%512;
							iTRb  = (iTRb  + 512)%512;

							img->fw_refFrArr[img->block_y+j][img->block_x+i]=0; 
							img->bw_refFrArr[img->block_y+j][img->block_x+i]=0;

							j4 = img->block_y+j;
							i4 = img->block_x+i;

							for (ii=0; ii < 2; ii++)
							{
								if(img->mv[img->block_x+i+4][img->block_y+j][ii] < 0)
								{
									img->fw_mv[i4+BLOCK_SIZE][j4][ii] =  -(((16384/iTRp)*(1-iTRb*img->mv[img->block_x+i+4][img->block_y+j][ii])-1)>>14);
									img->bw_mv[i4+BLOCK_SIZE][j4][ii] = ((16384/iTRp)*(1-iTRd*img->mv[img->block_x+i+4][img->block_y+j][ii])-1)>>14;
								}
								else
								{
									img->fw_mv[i4+BLOCK_SIZE][j4][ii] = ((16384/iTRp)*(1+iTRb*img->mv[img->block_x+i+4][img->block_y+j][ii])-1)>>14;
									img->bw_mv[i4+BLOCK_SIZE][j4][ii] = -(((16384/iTRp)*(1+iTRd*img->mv[img->block_x+i+4][img->block_y+j][ii])-1)>>14);
								}

							}
						} 
					}
			}

			img_block_y = img->block_y;

			i0+=max(1,step_h0);
		}
		j0+=max(1,step_v0);
	}


	//=====  READ BACKWARD MOTION VECTORS =====
	currSE.type = SE_MVD;

	currSE.mapping = linfo_se;

	img_block_y = img->block_y;

	for (j0=0; j0<2; )
	{
		if(currMB->mb_type!=I_MB)
		{				
			step_h0         = (BLOCK_STEP[(currMB->mb_type==P8x8)? 4 : currMB->mb_type][0]);
			step_v0         = (BLOCK_STEP[(currMB->mb_type==P8x8)? 4 : currMB->mb_type][1]);
		}

		if((currMB->mb_type==I_MB&&j0==0)) 
		{ j0 += 1; continue;}


		for (i0=0; i0<2; )
		{
			k=2*j0+i0;

			if ((currMB->b8pdir[k]==1 || currMB->b8pdir[k]==2) && (currMB->b8mode[k]!=0))//has backward vector
			{
				mv_mode  = currMB->b8mode[k];
				step_h   = BLOCK_STEP [mv_mode][0];
				step_v   = BLOCK_STEP [mv_mode][1];
				refframe = img->bw_refFrArr[img->block_y+j0][img->block_x+i0]; // always 0
				use_scaled_mv = 0;
				if(currMB->b8pdir[k]==2)
				{
					fw_refframe = img->fw_refFrArr[img->block_y+j0][img->block_x+i0];
					current_tr  = 2*(img->pic_distance/2);

				}
				for (j=j0; j<j0+step_v0; j+=step_v)
					for (i=i0; i<i0+step_h0; i+=step_h)
					{
						j4 = img->block_y+j;
						i4 = img->block_x+i;
						SetMotionVectorPredictor (img, pmv, pmv+1, refframe, img->bw_refFrArr, img->bw_mv, i, j, 8*step_h, -1);//Lou 1016
						for (k=0; k < 2; k++) 
						{
#if TRACE
							snprintf(currSE.tracestring, TRACESTRING_SIZE, "BMVD (pred %d)",pmv[k]);
#endif
							img->subblock_x = i; // position used for context determination
							img->subblock_y = j; // position used for context determination
							currSE.value2   = 2*k+1; // identifies the component; only used for context determination
							if(currMB->b8pdir[2*j0+i0] == 2)
							{				  
								int delta_P,iTRp,DistanceIndexFw,DistanceIndexBw,refframe,delta_PB;				  
								refframe = fw_refframe;
								delta_P = 2*(img->imgtr_next_P - img->imgtr_last_P);
								delta_P = (delta_P + 512)%512;    
								iTRp = (refframe+1)*delta_P;  //the lates backward reference
								delta_PB = 2*(img->pic_distance - img->imgtr_last_P);  
								delta_PB = (delta_PB + 512)%512;                       
								iTRp     = (iTRp + 512)%512;                           
								DistanceIndexFw = delta_PB;							    
								DistanceIndexBw    = (iTRp - DistanceIndexFw+512)%512; 
								curr_mvd = - ((img->fw_mv[i4+BLOCK_SIZE][j4][k]*DistanceIndexBw*(512/DistanceIndexFw)+256)>>9); 
								vec=curr_mvd;           /* find motion vector */
								curr_mvd = curr_mvd - pmv[k];
							}
							else
							{
								dP = &(currSlice->partArr[0]);
								currSE.reading = readMVD_AEC;
								img->subblock_x = i; // position used for context determination
								img->subblock_y = j; // position used for context determination
								currSE.value2   = (k<<1) +1; // identifies the component; only used for context determination
								dP->readSyntaxElement(&currSE,img,dP);

								curr_mvd = currSE.value1; 
								vec=curr_mvd+pmv[k];           /* find motion vector */
								//CHECKMVDRANGE                  // mvrange, ITM
							}

							for(ii=0;ii<step_h;ii++)
								for(jj=0;jj<step_v;jj++)
									img->bw_mv[i4+ii+BLOCK_SIZE][j4+jj][k]=vec;

							/* store (oversampled) mvd */
							for (l=0; l < step_v; l++) 
								for (m=0; m < step_h; m++)  
									currMB->mvd[1][j+l][i+m][k] =  curr_mvd;
						}
					}
			}
			i0+=max(1,step_h0);
		}
		j0+=max(1,step_v0);

	}
}

/*
*************************************************************************
* Function:Get coded block pattern and coefficients (run/level)
from the bitstream
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/

void readCBPandCoeffsFromStream(img_params *img)
{
	int i,j;
	int mb_nr = img->current_mb_nr; //GBimg->current_mb_nr;
	int b8, b4, b8add, b4add;
	int bsize;
	const int *IVC_SCAN;
	int coef_num;
	int  m2,jg2;
	Macroblock *currMB = &mb_data[mb_nr];

	int block_x,block_y;
	Slice *currSlice = img->currentSlice;
	int			level, run, coef_ctr,len ,k ,i0,j0,uv,val,qp;
	int			shift,QPI,sum;
	int           boff_x,boff_y,start_scan;  
	SyntaxElement currSE;   
	DataPartition *dP;

	int qp_per    = (img->qp-MIN_QP)/6;
	int qp_rem    = (img->qp-MIN_QP)%6;
	int qp_per_uv = QP_SCALE_CR[img->qp-MIN_QP]/6;
	int qp_rem_uv = QP_SCALE_CR[img->qp-MIN_QP]%6;

	DCT_Pairs=-1;

	qp_per    = (img->qp-MIN_QP)/6;
	qp_rem    = (img->qp-MIN_QP)%6;
	qp_per_uv = QP_SCALE_CR[img->qp-MIN_QP]/6;
	qp_rem_uv = QP_SCALE_CR[img->qp-MIN_QP]%6;
	currMB->qp = img->qp;
	qp  = currMB->qp;       

	if (currMB->trans_type == TRANS_2Nx2N) {
		b8add = 4;
	} else {
		b8add = 1;
	}

	// luma coefficients
	for (b8 = 0; b8 < 4; b8 += b8add) {
		if (currMB->trans_type == TRANS_2Nx2N) {
			bsize = 16;
			coef_num = 256;
			b4add = 4;
			IVC_SCAN = IVC_SCAN16;
		} else if(currMB->splite_flag[b8] == 0) {
			bsize = 8;
			coef_num = 64;
			b4add = 4;
			IVC_SCAN = IVC_SCAN8;
		} else {
			bsize = 4;
			coef_num = 16;
			b4add = 1;
			IVC_SCAN = IVC_SCAN4;
		}

		DCT_Block_Size = bsize;

		for (b4 = 0; b4 < 4; b4 += b4add) {
			if (currMB->cbp & (1 << (4 * b8 + b4))) {
				// === set offset in current macroblock ===
				boff_x = 8 * (b8 % 2) + 4 * (b4 % 2);
				boff_y = 8 * (b8 / 2) + 4 * (b4 / 2);

				start_scan = 0; // take all coeffs
				coef_ctr = start_scan - 1;
				level = 1;
				img->is_v_block = 0;
				img->is_intra_block = IS_INTRA(currMB);
				for (k = start_scan; (k < coef_num + 1) && (level != 0); k++) {
					//============ read =============
					currSE.context = LUMA_8x8;
					currSE.type = (IS_INTRA(currMB)) ? SE_LUM_AC_INTRA : SE_LUM_AC_INTER;
#if TRACE
					sprintf(currSE.tracestring, "Luma8x8 sng ");
#endif
					dP = &(currSlice->partArr[0]);
					currSE.reading = readRunLevel_AEC_Ref;
					dP->readSyntaxElement(&currSE, img, dP);
					level = currSE.value1;
					run = currSE.value2;
					len = currSE.len;

					//============ decode =============
					if (level != 0) {
						coef_ctr += run + 1;
						i = IVC_SCAN[coef_ctr] % bsize;
						j = IVC_SCAN[coef_ctr] / bsize;

						shift = IQ_SHIFT[qp];
						QPI = IQ_TAB[qp];
						val = level;
						sum = (val*QPI + (1 << (shift - 1))) >> shift;

						img->m7[boff_x + i][boff_y + j] = sum;
					}
				}
			}
		}
	}

	// chroma
	m2 =img->mb_x*2;
	jg2=img->mb_y*2;

	DCT_Block_Size = 8;
	uv=-1;
	block_y=4;
	qp = QP_SCALE_CR[currMB->qp];
	for (block_x=0; block_x < 4; block_x += 2)
	{
		uv++;
		if((currMB->cbp>>(4*(uv+4)))&0x1)
		{
			coef_ctr=-1;
			level=1;
			img->subblock_x    = 0;
			img->subblock_y    = 0; 
			currSE.context     = CHROMA_AC;
			currSE.type        = (IS_INTRA(currMB) ? SE_CHR_AC_INTRA : SE_CHR_AC_INTER);   // element is of type DC
			dP = &(currSlice->partArr[0]);
			currSE.reading = readRunLevel_AEC_Ref;
			img->is_v_block    = uv;
			img->is_intra_block=IS_INTRA(currMB);
			for(k=0;(k<65) && (level!=0);k++)
			{
#if TRACE
				snprintf(currSE.tracestring, TRACESTRING_SIZE, "AC chroma 8X8 ");
#endif
				dP->readSyntaxElement(&currSE,img,dP);
				level = currSE.value1;
				run   = currSE.value2;
				len   = currSE.len;
				if (level != 0)                     // leave if len=1
				{
					coef_ctr=coef_ctr+run+1;
					i0 = IVC_SCAN8[coef_ctr] % 8;
					j0 = IVC_SCAN8[coef_ctr] / 8;

					shift = IQ_SHIFT[qp];
					QPI   = IQ_TAB[qp]; 
					val   = level;
					sum = (val*QPI+(1<<(shift-1)) )>>shift;

					img->m8[uv][i0][j0] = sum;
				} //level!=0
			} //end k=0~64  
		}
	}
}

/*
*************************************************************************
* Function:decode one macroblock
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/

int decode_one_macroblock(img_params *img)
{
	unsigned char edgepixu[40];  
#define EPU (edgepixu+20)      
	unsigned char edgepixv[40];  
#define EPV (edgepixv+20)
	unsigned char *pedge;
	int bs_x=8;
	int bs_y=8;
	pel_t tmp_block[64];
	pel_t tmp_blockbw[64];

	int x=0,y=0,img_b8_y=0,img_b8_x=0;
	int img_b4_x, img_b4_y;
	int uv;
	int vec1_x=0,vec1_y=0,vec2_x=0,vec2_y=0;
	int ioff,joff;
	int curr_blk[MB_SIZE * MB_SIZE];  //SW for IVC
	int tmp;
	int b8;
	uchar_t *pSrc;
	pel_t bw_pred[16], fw_pred[16];
	
	int mv_mul;
	int mv_x, mv_y, mv_x_bw, mv_y_bw;
	int if_pos_x, if_pos_y, if_pos_x_bw, if_pos_y_bw;
	int i_ref = img->iStride;
	int i_refc = img->iStrideC;

	Macroblock *currMB   = &mb_data[img->current_mb_nr];//GB current_mb_nr];
	int refframe, fw_refframe, bw_refframe, mv_mode, pred_dir; // = currMB->ref_frame;
	int bframe = (img->type==B_IMG);

	pel_t *predblk;
	int mb_nr             = img->current_mb_nr;//GBimg->current_mb_nr;
	int mb_width          = img->PicWidthInMbs;
	bool mb_available_up;
	bool mb_available_left;

	int fwd_refframe_offset,bwd_refframe_offset;

	int mb_available_up_right =((img->mb_y==0)||(img->mb_x==img->width/MB_SIZE-1))  ? 
		0 : (mb_data[mb_nr].slice_nr == mb_data[mb_nr-mb_width+1].slice_nr);                                    

	mb_available_up   = (img->mb_y == 0) ? 0 : (mb_data[mb_nr].slice_nr == mb_data[mb_nr-mb_width].slice_nr);
	mb_available_left = (img->mb_x == 0) ? 0 : (mb_data[mb_nr].slice_nr == mb_data[mb_nr-1].slice_nr); 

	if(bframe)
	{
		int current_tr = 2*(img->pic_distance/2);

		if(img->imgtr_next_P <= current_tr)
			fwd_refframe_offset = 0;
		else 
			fwd_refframe_offset = 1;
	}
	else
	{
		fwd_refframe_offset = 0;
	}

	if (bframe)
	{
		bwd_refframe_offset = 0;
	}

	mv_mul=4;

	// luma decoding **************************************************

	if (IS_INTRA (currMB)) {
		if (currMB->trans_type == TRANS_2Nx2N)
		{
			get_curr_blk(0, 0, img, curr_blk, 16);
			tmp = intrapred(img, imgY_rec, (img->mb_x << 4), (img->mb_y << 4), 16);
			if (tmp == SEARCH_SYNC) {
				return SEARCH_SYNC;                   /* bit error */
			}
			idct_dequant_B8(0, 0, curr_blk, img, 16);
		} 
		else {
			for (b8 = 0; b8 < 4; b8++) {
				int b4;
				int blk_cnt = currMB->splite_flag[b8] ? 4 : 1;
				int bsize = currMB->splite_flag[b8] ? 4 : 8;
				for (b4 = 0; b4 < blk_cnt; b4++) {
					int img_x = 16 * img->mb_x + 8 * (b8 & 1) + 4 * (b4 & 1);
					int img_y = 16 * img->mb_y + 8 * (b8 / 2) + 4 * (b4 / 2);
					get_curr_blk(b8, b4, img, curr_blk, bsize);

					tmp = intrapred(img, imgY_rec, img_x, img_y, bsize);
					if (tmp == SEARCH_SYNC) { 
						return SEARCH_SYNC;                
					}

					idct_dequant_B8(b8, b4, curr_blk, img, bsize);
				}
			}
		}
	} 
	else {
		for (b8 = 0; b8 < 4; b8++) {
			x = b8 % 2;
			y = b8 / 2;

			joff = y * 8;
			ioff = x * 8;
			img_b8_x = img->block_x + x;
			img_b8_y = img->block_y + y;

			predblk = img->predblk + joff*16 + ioff;

			mv_mode = currMB->b8mode[b8];
			pred_dir = currMB->b8pdir[b8];
			get_pred_mv(img, currMB, b8, bframe, img_b8_x, img_b8_y, &vec1_x, &vec1_y, &vec2_x, &vec2_y, &refframe, &fw_refframe, &bw_refframe);

			if(pred_dir!=2){
				if (!bframe){
					get_luma_block(vec1_x, vec1_y, img, tmp_block,8, p_mref[refframe], i_ref);
					get_luma_block(vec2_x, vec2_y, img, tmp_blockbw,8, p_mref[refframe], i_ref);
				}
				else // !! for B MB one direction   
				{
					if (!pred_dir){  // !! forward
						get_luma_block( vec1_x, vec1_y, img, tmp_block, 8, f_ref_frm[0], i_ref);
					}
					else{ // !! backward
						get_luma_block( vec1_x, vec1_y, img, tmp_block, 8, b_ref_frm[0], i_ref);
					}
				}

				if ((!bframe) && (mv_mode != 0) && (pred_dir == 3)){
					g_funs_handle.avg_pel(predblk, MB_SIZE, tmp_block, 8, tmp_blockbw, 8, 8, 8);
				}
				else{
					g_funs_handle.com_cpy(tmp_block, 8, predblk, MB_SIZE, 8, 8);
				}
			}
			else{
				get_luma_block(vec1_x, vec1_y, img, tmp_block, 8, f_ref_frm[0], i_ref);
				get_luma_block(vec2_x, vec2_y, img, tmp_blockbw, 8, b_ref_frm[0], i_ref);
				g_funs_handle.avg_pel(predblk, MB_SIZE, tmp_block, 8, tmp_blockbw, 8, 8, 8);
			}

			if (currMB->trans_type == TRANS_NxN) {
				get_curr_blk(b8, 0, img, curr_blk, 8);
				idct_dequant_B8(b8, 0, curr_blk, img, 8);
			}
		}

		if (currMB->trans_type == TRANS_2Nx2N) {
			get_curr_blk (0, 0, img, curr_blk, 16);
			idct_dequant_B8 (0, 0, curr_blk, img, 16);
		}
	}

	// chroma decoding *******************************************************
	for(uv=0;uv<2;uv++){
		if (IS_INTRA (currMB)){
			if (uv==0){
				pedge = EPU;
				pSrc = imgU_rec;
			}
			else{
				pedge = EPV;
				pSrc = imgV_rec;
			}

			if(mb_available_up){
				for(x=0;x<bs_x;x++)
					pedge[x+1]=pSrc[(img->pix_c_y-1)*img->iStrideC + img->pix_c_x+x];

				if(mb_available_up_right){
					for(x=0;x<bs_y;x++)
						pedge[1+x+bs_x]=pSrc[(img->pix_c_y-1)*img->iStrideC + img->pix_c_x+bs_x+x];
				}
				else{
					for(x=0;x<bs_y;x++)	
						pedge[1+x+bs_x]=pedge[bs_x];  //bs_x=8; EPU[9~16]=r[8]  
				}

				pedge[0]=pSrc[(img->pix_c_y-1)*img->iStrideC + img->pix_c_x];
			}

			if(mb_available_left){
				for(y=0;y<bs_y;y++)
					pedge[-1-y]=pSrc[(img->pix_c_y+y)*img->iStrideC + img->pix_c_x-1];

				for(y=0;y<bs_x;y++)
					pedge[-1-y-bs_y]=pedge[-bs_y];

				pedge[0]=pSrc[(img->pix_c_y)*img->iStrideC + img->pix_c_x-1];
			}

			if(mb_available_up&&mb_available_left)
				pedge[0]=pSrc[(img->pix_c_y-1)*img->iStrideC + img->pix_c_x-1];

			//lowpass (Those elements that are not needed will not disturb)
			if(currMB->c_ipred_mode == DC_PRED_8)
				xIntraPredFilter(pedge);
		}

		for (b8=0;b8<4;b8++) // loop over 4x4 chroma blocks
		{
			y = b8/2;
			joff = y << 2;
			img_b4_y=img->block_y+y;

			x = b8%2;
			ioff=x<<2;
			img_b4_x=img->block_x+x;

			predblk = img->predblk + joff*16 + ioff;

			// PREDICTION
			if (currMB->mb_type==I_MB){
				predblk = img->predblk + joff*16 + ioff;
				intra_pred_chroma(pedge, predblk, MB_SIZE, currMB->c_ipred_mode, ioff, joff, mb_available_up, mb_available_left);
			}
			else{
				mv_mode  = currMB->b8mode[b8];
				pred_dir = currMB->b8pdir[b8];
				get_chroma_mv_ref(img, currMB, b8, bframe, img_b4_x, img_b4_y, &mv_x, &mv_y, &mv_x_bw, &mv_y_bw, &refframe, &fw_refframe, &bw_refframe);

				if_pos_y = mv_y & 0x7;
				if_pos_x = mv_x & 0x7;
				if_pos_y_bw = mv_y_bw & 0x7;
				if_pos_x_bw = mv_x_bw & 0x7;

				mv_y += ((img->pix_c_y+joff)<<3);
				mv_x += ((img->pix_c_x+ioff)<<3);
				mv_y_bw += ((img->pix_c_y+joff)<<3);
				mv_x_bw += ((img->pix_c_x+ioff)<<3);

				if (pred_dir != 2) {
					if(!bframe){
						if((mv_mode != 0) && (pred_dir == 3)){
							get_chroma_block(fw_pred, 4, mv_x, mv_y, if_pos_x, if_pos_y, p_mcef[refframe][uv], i_refc);
							get_chroma_block(bw_pred, 4, mv_x_bw, mv_y_bw, if_pos_x_bw, if_pos_y_bw, p_mcef[refframe][uv], i_refc);
							g_funs_handle.avg_pel(predblk, MB_SIZE, fw_pred, 4, bw_pred, 4, 4, 4);
						}
						else{
							get_chroma_block(predblk, MB_SIZE, mv_x, mv_y, if_pos_x, if_pos_y, p_mcef[refframe][uv], i_refc);
						}
					}
					else{
						refframe = 0;
						if(!pred_dir) {
							get_chroma_block(predblk, MB_SIZE, mv_x, mv_y, if_pos_x, if_pos_y, f_ref_frm[uv+1], i_refc);
						}
						else{
							get_chroma_block(predblk, MB_SIZE, mv_x, mv_y, if_pos_x, if_pos_y, b_ref_frm[uv+1], i_refc);
						}
					}
				}
				else{
					get_chroma_block(fw_pred, 4, mv_x, mv_y, if_pos_x, if_pos_y, f_ref_frm[uv+1], i_refc);
					get_chroma_block(bw_pred, 4, mv_x_bw, mv_y_bw, if_pos_x_bw, if_pos_y_bw, b_ref_frm[uv+1], i_refc);
					g_funs_handle.avg_pel(predblk, MB_SIZE, fw_pred, 4, bw_pred, 4, 4, 4);
				}
			}
		}

		get_curr_blk (4+uv, 0, img, curr_blk, 8);
		idct_dequant_B8 (4+uv, 0, curr_blk, img, 8);
	}
	return 0;
}

/*!
************************************************************************
* \brief
*    returns the x and y sample coordinates for a given MbAddress
************************************************************************
*/
void get_mb_pos (int mb_addr, int *x, int*y)
{
	*x = (mb_addr % img->PicWidthInMbs);
	*y = (mb_addr / img->PicWidthInMbs);
	(*x) *= MB_SIZE;
	(*y) *= MB_SIZE;
}

/*!
************************************************************************
* \brief
*    get neighbouring positions. 
* \param curr_mb_nr
*   current macroblock number (decoding order)
* \param xN
*    input x position
* \param yN
*    input y position
* \param luma
*    1 if luma coding, 0 for chroma
* \param pix
*    returns position informations
* \author
*    added by 
************************************************************************
*/
void getNeighbour(int curr_mb_nr, int xN, int yN, int luma, PixelPos *pix)
{
	Macroblock *currMb = &mb_data[curr_mb_nr];
	int maxWH;

	if (luma)
		maxWH = 16;
	else
		maxWH = 8;

	if ((xN<0)&&(yN<0))
	{
		pix->mb_addr   = currMb->mbAddrD;
		pix->available = currMb->mbAvailD;
	}
	else
		if ((xN<0)&&((yN>=0)&&(yN<maxWH)))
		{
			pix->mb_addr  = currMb->mbAddrA;
			pix->available = currMb->mbAvailA;
		}
		else
			if (((xN>=0)&&(xN<maxWH))&&(yN<0))
			{
				pix->mb_addr  = currMb->mbAddrB;
				pix->available = currMb->mbAvailB;
			}
			else
				if (((xN>=0)&&(xN<maxWH))&&((yN>=0)&&(yN<maxWH)))
				{
					pix->mb_addr  = curr_mb_nr;
					pix->available = 1;
				}
				else
					if ((xN>=maxWH)&&(yN<0))
					{
						pix->mb_addr  = currMb->mbAddrC;
						pix->available = currMb->mbAvailC;
					}
					else 
					{
						pix->available = 0;
					}
					if (pix->available)
					{
						pix->x = (xN + maxWH) % maxWH;
						pix->y = (yN + maxWH) % maxWH;
						get_mb_pos(pix->mb_addr, &(pix->pos_x), &(pix->pos_y));
						if (luma)
						{
							pix->pos_x += pix->x;
							pix->pos_y += pix->y;
						}
						else
						{
							pix->pos_x = (pix->pos_x/2) + pix->x;
							pix->pos_y = (pix->pos_y/2) + pix->y;
						}
					}
}


/*!
************************************************************************
* \brief
*    get neighbouring  get neighbouring 8x8 luma block
* \param curr_mb_nr
*   current macroblock number (decoding order)
* \param block_x
*    input x block position
* \param block_y
*    input y block position
* \param rel_x
*    relative x position of neighbor
* \param rel_y
*    relative y position of neighbor
* \param pix
*    returns position informations
* \author
*    added by 
************************************************************************
*/

void getLuma8x8Neighbour (int curr_mb_nr, int b8_x, int b8_y, int rel_x, int rel_y, PixelPos *pix)
{
	int x = 8* b8_x + rel_x;
	int y = 8* b8_y + rel_y;

	int b8, b8_dest;   
	int pdir, pdir_dest;

	getNeighbour(curr_mb_nr, x, y, 1, pix);

	if (pix->available)
	{
		b8=b8_x+b8_y*2;
		b8_dest=pix->x/8+pix->y/8*2;
		pdir=mb_data[curr_mb_nr].b8pdir[b8];
		pdir_dest=mb_data[pix->mb_addr].b8pdir[b8_dest];
		if((pdir==0 && pdir_dest==1) || (pdir==1 && pdir_dest==0) || (pdir==2 && pdir_dest==1)||(pdir==1 && pdir_dest==2))
			pix->available=0;

		pix->x /= 8;
		pix->y /= 8;
		pix->pos_x /= 8;
		pix->pos_y /= 8;
	}
}

//!EDIT end <added by  AEC